package com.xushu.springframework;

import com.xushu.app.AppConfig;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.rmi.registry.Registry;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class XushuApplicationContext {
    private Class configClass;
    private Map<String, BeanDefinition> beanDefinitionMap=new LinkedHashMap<>();
    // 单例池 一级缓存  完整bean
    private Map<String, Object> singletonObjects=new ConcurrentHashMap<>();
    //  二级缓存 :早期bean
    private Map<String, Object> earlySingletonObjects=new ConcurrentHashMap<>();
    //  三级缓存：函数式接口
    private Map<String, ObjectFactory> factoriesObjects=new ConcurrentHashMap<>();


    // BeanPostProcessor集合
    private List<BeanPostProcessor> beanPostProcessors=new ArrayList<>();


    public XushuApplicationContext(Class<AppConfig> appConfigClass) throws Exception {
        // 读取配置类(配置解析成beandefinition)
        this.configClass=appConfigClass;
        // 解析配置类的扫描包
        scan(configClass);

        // 注册beanPostProcessor
        registryBeanPostProcessor();

        // 一个个创建单例bean
        preInstantiateSingletons();
    }

    // 注册BeanPostProcessor
    private void registryBeanPostProcessor() throws Exception {
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            Class beanClass = beanDefinition.getBeanClass();
            if(BeanPostProcessor.class.isAssignableFrom(beanClass)){
                BeanPostProcessor bean = (BeanPostProcessor) getBean(beanName);
                beanPostProcessors.add(bean);
            }
        }
    }

    // 预实例化单例bean
    private void preInstantiateSingletons() throws Exception {
        for (String beanName : beanDefinitionMap.keySet()) {

            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            // 不是懒加载&&是单例
            if(!beanDefinition.isLazy() && beanDefinition.isSingleton()){
                getBean(beanName);
            }


        }
    }

    /*public Object getBean(Class clazz){
        // 循环所有的beanDefinitionMap
        // 根据beandefinition中beanClass
    }*/

    // 获取/创建bean   A
    public  Object getBean(String beanName) throws Exception{
        // 获取单例bean
        Object bean= getSingleton(beanName);
        if(bean!=null){
            return bean;
        }

        synchronized (singletonObjects) {

            bean= getSingleton(beanName);
            if(bean!=null){
                return bean;
            }

            // 如果没有获取到就创建
            // 1. 实例化  new A    new B
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            Class beanClass = beanDefinition.getBeanClass();
            Object beanInstance = beanClass.getConstructor().newInstance();

            //  只有循环依赖的时候才执行
            // 出口
            Object finalBeanInstance = beanInstance;
            // (只有单例bean才会进行缓存）
            factoriesObjects.put(beanName,() -> {

                for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
                    if(beanPostProcessor instanceof SmartInstantiationAwareBeanPostProcessor) {
                       return ((SmartInstantiationAwareBeanPostProcessor)beanPostProcessor)
                                .getEarlyBeanReference(finalBeanInstance, beanName);
                    }
                }
                return finalBeanInstance;
            });
            // 出口
            earlySingletonObjects.put(beanName, beanInstance);

            // 2.属性注入 A.b  B.a byname bytype constructor default(@autowired bytype byname )
            for (Field declaredField : beanClass.getDeclaredFields()) {
                if (declaredField.isAnnotationPresent(Autowired.class)) {
                    // 根据@autowired的byname
                    String name = declaredField.getName();
                    // 依赖注入的bean的对象 getBean(b)   getBean(a)
                    Object dependBean = getBean(name);
                    declaredField.setAccessible(true);
                    declaredField.set(beanInstance, dependBean);
                }
            }


            // 初始化前
            for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
                beanInstance = beanPostProcessor.postProcessBeforeInitialization(beanInstance, beanName);
            }

            // 3.初始化
            if (beanInstance instanceof InitializingBean) {
                // 回调
                ((InitializingBean) beanInstance).afterPropertiesSet();
            }

            // 初始化后
            for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
                beanInstance = beanPostProcessor.postProcessAfterInitialization(beanInstance, beanName);
            }


            // 4. 缓存单例池中
            singletonObjects.put(beanName, beanInstance);
            earlySingletonObjects.remove(beanName);

            return beanInstance;
        }
    }

    // 获取单例bean
    private Object getSingleton(String beanName) {
        if(singletonObjects.containsKey(beanName)){
            return  singletonObjects.get(beanName);
        }

        synchronized (singletonObjects) {
            // 出口   二级缓存有=当前是循环依赖
            if (earlySingletonObjects.containsKey(beanName)) {

                return earlySingletonObjects.get(beanName);
            }
            // 出口   二级缓存有=当前是循环依赖
            if (factoriesObjects.containsKey(beanName)) {

                ObjectFactory objectFactory = factoriesObjects.get(beanName);
                Object aopBean = objectFactory.getObject();
                earlySingletonObjects.put(beanName,aopBean);
                factoriesObjects.remove(beanName);
                return aopBean;
            }
        }
        return null;
    }


    // 扫描包
    private void scan(Class configClass) throws ClassNotFoundException {
        // 拿到配置类@ComponentScan
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan annotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            // 拿到扫描的包名（可以不设置扫描包，注解所在类的包当做扫描包）
            String value = annotation.value();

            // 转换为物理路径   com.xushu.app=>com/xushu/app
            String path = value.replaceAll("\\.", "/");

            // 获取绝对路径
            ClassLoader classLoader = this.getClass().getClassLoader();
            // 目录
            URL resource = classLoader.getResource(path);
            // 获取目录IO对象
            File file = new File(resource.getFile());

            // 扫描到所有的类文件
            List<File> classFiles=new ArrayList<>();

            if (file.isDirectory()) {
                // 读取所有的文件
                for (File f : file.listFiles()) {

                    if(f.isDirectory()){
                        for (File f1 : f.listFiles()) {
                            classFiles.add(f1);
                        }
                    }
                    else{
                        classFiles.add(f);
                    }

                }
            }

            // 是个是一个bean
            //file对象转换成Class对象
            for (File classFile : classFiles) {
                //D:\xxx\com\xushu\app\service\OrderService.java
                String absolutePath = classFile.getAbsolutePath();
                //com\xushu\app\service\OrderService
                //com.xushu.app.service.OrderService
                String beanClassName = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"))
                        .replaceAll("\\\\", ".");

                Class<?> beanClass = classLoader.loadClass(beanClassName);

                // 是一个 bean
                if(beanClass.isAnnotationPresent(Component.class)){

                    // 解析beandefinition
                    BeanDefinition beanDefinition = new BeanDefinition();

                    beanDefinition.setBeanClass(beanClass);
                    // 解析懒加载
                    beanDefinition.setLazy(beanClass.isAnnotationPresent(Lazy.class));
                    // 解析单例、多例
                    if (beanClass.isAnnotationPresent(Scope.class)) {
                        Scope scopeAnnotation = beanClass.getAnnotation(Scope.class);
                        beanDefinition.setScope(scopeAnnotation.value());
                    }
                    else{
                        beanDefinition.setScope("singleton");
                    }

                    // (在spring还要解析更多的bean定义信息 autowire abstract dependsOn....

                    Component componentAnno = beanClass.getAnnotation(Component.class);
                    String beanName=componentAnno.value();
                    if(beanName.isEmpty()){
                        // 默认类名首字母小写作为beanName
                        // UserService  ---> userService
                        // OAService  ---> OAService
                        beanName = Introspector.decapitalize(beanClass.getSimpleName());
                    }

                    // key: beanName  value:beanDefinition
                    beanDefinitionMap.put(beanName, beanDefinition);
                }

            }

            // 存储到beanDefinitionMap

        }

        // (Spring: 解析@Import  @Bean)  ...
        // (Spring: @EnableAspectJAutoProxy--> 导入AutoProxyCreatorBeanPostProcessor)
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setBeanClass(AutoProxyCreatorBeanPostProcessor.class);
        beanDefinitionMap.put("autoProxyCreatorBeanPostProcessor", beanDefinition);

    }
}
